package org.black.phoneUtility.sms.reply.content.contentProvider;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.CountDownLatch;

import org.black.phoneUtility.database.sqlite.PhoneUtilitySQLiteOpenHelper;
import org.black.phoneUtility.database.sqlite.PhoneUtilityTransaction;
import org.black.phoneUtility.sms.reply.provider.SmsReplyContract;

import android.content.ContentProvider;
import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.OperationApplicationException;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.database.sqlite.SQLiteTransactionListener;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;

public class SmsReplyContentProvider extends ContentProvider implements
		SQLiteTransactionListener {
	static final String SMS_REPLY_CONTACT_TAG = "sms_reply_contact_tag";

	private ThreadLocal<PhoneUtilityTransaction> phoneUtilityTransactionHolder = new ThreadLocal<PhoneUtilityTransaction>();
	private volatile CountDownLatch writeAccessLatch;

	private static final int SMS_REPLY_GLOBAL_SETTING = 129;
	private static final int SMS_REPLY_GLOBAL_SETTING_ID = 130;
	private static final int SMS_REPLY = 131;
	private static final int SMS_REPLY_ID = 132;
	private static final int SMS_REPLY_TIMES_MODE = 133;
	private static final int SMS_REPLY_TIMES_MODE_ID = 134;
	private static final int RESPONSE_NUMBER_FROM = 135;
	private static final int RESPONSE_NUMBER_FROM_ID = 136;
	private static final int REPLY_TO_SPECIFIC_NUMBER = 137;
	private static final int REPLY_TO_SPECIFIC_NUMBER_ID = 138;
	private static final int NONE_REPLY_NUMBER = 139;
	private static final int NONE_REPLY_NUMBER_ID = 140;
	private static final int ACTIVATION_RECORD = 141;
	private static final int ACTIVATION_RECORD_ID = 142;
	private static final int SMS_REPLY_REPLY_HISTORY = 143;
	private static final int SMS_REPLY_REPLY_HISTORY_ID = 144;
	private static final int SMS_REPLY_APP_WIDGET_ID = 145;
	private static final int SMS_REPLY_APP_WIDGET_ID_ID = 146;

	private static final String LOG_TAG = SmsReplyContentProvider.class
			.getSimpleName();
	private static final boolean VERBOSE_LOGGING = Log.isLoggable(LOG_TAG,
			Log.VERBOSE);

	private PhoneUtilitySQLiteOpenHelper phoneUtilitySQLiteOpenHelper;

	private static final UriMatcher uriMatcher = new UriMatcher(
			UriMatcher.NO_MATCH);
	static {
		uriMatcher
				.addURI(SmsReplyContract.AUTHORITY,
						SmsReplyContract.SmsReplyGlobalSettings.SMS_REPLY_GLOBAL_SETTINGS,
						SMS_REPLY_GLOBAL_SETTING);
		uriMatcher
				.addURI(SmsReplyContract.AUTHORITY,
						SmsReplyContract.SmsReplyGlobalSettings.SMS_REPLY_GLOBAL_SETTINGS
								+ "/#", SMS_REPLY_GLOBAL_SETTING_ID);

		uriMatcher.addURI(SmsReplyContract.AUTHORITY,
				SmsReplyContract.SmsReplies.SMS_REPLIES, SMS_REPLY);
		uriMatcher.addURI(SmsReplyContract.AUTHORITY,
				SmsReplyContract.SmsReplies.SMS_REPLIES + "/#", SMS_REPLY_ID);

		uriMatcher.addURI(SmsReplyContract.AUTHORITY,
				SmsReplyContract.ReplyTimesModes.REPLY_TIMES_MODES,
				SMS_REPLY_TIMES_MODE);
		uriMatcher.addURI(SmsReplyContract.AUTHORITY,
				SmsReplyContract.ReplyTimesModes.REPLY_TIMES_MODES + "/#",
				SMS_REPLY_TIMES_MODE_ID);

		uriMatcher.addURI(SmsReplyContract.AUTHORITY,
				SmsReplyContract.ResponseNumberFrom.RESPONSE_NUMBER_FROMS,
				RESPONSE_NUMBER_FROM);
		uriMatcher.addURI(SmsReplyContract.AUTHORITY,
				SmsReplyContract.ResponseNumberFrom.RESPONSE_NUMBER_FROMS
						+ "/#", RESPONSE_NUMBER_FROM_ID);

		uriMatcher
				.addURI(SmsReplyContract.AUTHORITY,
						SmsReplyContract.ReplyToSpecificNumbers.REPLY_TO_SPECIFIC_NUMBERS,
						REPLY_TO_SPECIFIC_NUMBER);
		uriMatcher
				.addURI(SmsReplyContract.AUTHORITY,
						SmsReplyContract.ReplyToSpecificNumbers.REPLY_TO_SPECIFIC_NUMBERS
								+ "/#", REPLY_TO_SPECIFIC_NUMBER_ID);

		uriMatcher.addURI(SmsReplyContract.AUTHORITY,
				SmsReplyContract.NoneReplyNumbers.NONE_REPLY_NUMBERS,
				NONE_REPLY_NUMBER);
		uriMatcher.addURI(SmsReplyContract.AUTHORITY,
				SmsReplyContract.NoneReplyNumbers.NONE_REPLY_NUMBERS + "/#",
				NONE_REPLY_NUMBER_ID);

		uriMatcher.addURI(SmsReplyContract.AUTHORITY,
				SmsReplyContract.ActivationRecords.ACTIVATION_RECORDS,
				ACTIVATION_RECORD);
		uriMatcher.addURI(SmsReplyContract.AUTHORITY,
				SmsReplyContract.ActivationRecords.ACTIVATION_RECORDS + "/#",
				ACTIVATION_RECORD_ID);

		uriMatcher.addURI(SmsReplyContract.AUTHORITY,
				SmsReplyContract.ReplyHistories.REPLY_HISTORIES,
				SMS_REPLY_REPLY_HISTORY);
		uriMatcher.addURI(SmsReplyContract.AUTHORITY,
				SmsReplyContract.ReplyHistories.REPLY_HISTORIES + "/#",
				SMS_REPLY_REPLY_HISTORY_ID);

		uriMatcher.addURI(SmsReplyContract.AUTHORITY,
				SmsReplyContract.SmsReplyAppWidgetIds.SMS_REPLY_APP_WIDGET_IDS,
				SMS_REPLY_APP_WIDGET_ID);
		uriMatcher.addURI(SmsReplyContract.AUTHORITY,
				SmsReplyContract.SmsReplyAppWidgetIds.SMS_REPLY_APP_WIDGET_IDS
						+ "/#", SMS_REPLY_APP_WIDGET_ID_ID);
	}

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		int result = 0;

		String tableName = null;
		int matchResult = uriMatcher.match(uri);
		switch (matchResult) {
		case SMS_REPLY_GLOBAL_SETTING:
		case SMS_REPLY_GLOBAL_SETTING_ID: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.GLOBAL_SETTINGS;
			break;
		}
		case SMS_REPLY:
		case SMS_REPLY_ID: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.REPLIES;
			switch (matchResult) {
			case SMS_REPLY:
				break;
			case SMS_REPLY_ID:
				String smsReplyId = uri.getLastPathSegment();

				selection = SmsReplyContract.SmsReplies._ID
						+ "="
						+ smsReplyId
						+ (TextUtils.isEmpty(selection) == false ? " AND ("
								+ selection + ')' : "");
				break;
			}
			break;
		}
		case SMS_REPLY_TIMES_MODE:
		case SMS_REPLY_TIMES_MODE_ID: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.REPLY_TIMES_MODE;
			switch (matchResult) {
			case SMS_REPLY_TIMES_MODE:
				break;
			case SMS_REPLY_TIMES_MODE_ID:
				String replyTimeModesId = uri.getLastPathSegment();

				selection = SmsReplyContract.ReplyTimesModes._ID
						+ "="
						+ replyTimeModesId
						+ (TextUtils.isEmpty(selection) == false ? " AND ("
								+ selection + ')' : "");
				break;
			}
			break;
		}
		case RESPONSE_NUMBER_FROM:
		case RESPONSE_NUMBER_FROM_ID: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.RESPONSE_NUMBER_FROM;
			switch (matchResult) {
			case RESPONSE_NUMBER_FROM:
				break;
			case RESPONSE_NUMBER_FROM_ID:
				String responseNumberFromId = uri.getLastPathSegment();

				selection = SmsReplyContract.ResponseNumberFrom._ID
						+ "="
						+ responseNumberFromId
						+ (TextUtils.isEmpty(selection) == false ? " AND ("
								+ selection + ')' : "");
				break;
			}
			break;
		}
		case REPLY_TO_SPECIFIC_NUMBER:
		case REPLY_TO_SPECIFIC_NUMBER_ID: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.REPLY_TO_SPECIFIC_NUMBER;
			switch (matchResult) {
			case REPLY_TO_SPECIFIC_NUMBER:
				break;
			case REPLY_TO_SPECIFIC_NUMBER_ID:
				String replyToSpecificId = uri.getLastPathSegment();

				selection = SmsReplyContract.ReplyToSpecificNumbers._ID
						+ "="
						+ replyToSpecificId
						+ (TextUtils.isEmpty(selection) == false ? " AND ("
								+ selection + ')' : "");
				break;
			}
			break;
		}
		case NONE_REPLY_NUMBER:
		case NONE_REPLY_NUMBER_ID: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.NONE_REPLY_NUMBER;
			switch (matchResult) {
			case NONE_REPLY_NUMBER:
				break;
			case NONE_REPLY_NUMBER_ID:
				String noneReplyId = uri.getLastPathSegment();

				selection = SmsReplyContract.NoneReplyNumbers._ID
						+ "="
						+ noneReplyId
						+ (TextUtils.isEmpty(selection) == false ? " AND ("
								+ selection + ')' : "");
				break;
			}
			break;
		}
		case ACTIVATION_RECORD:
		case ACTIVATION_RECORD_ID: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.ACTIVATION_RECORDS;
			switch (matchResult) {
			case ACTIVATION_RECORD:
				break;
			case ACTIVATION_RECORD_ID:
				String activationId = uri.getLastPathSegment();

				selection = SmsReplyContract.ActivationRecords._ID
						+ "="
						+ activationId
						+ (TextUtils.isEmpty(selection) == false ? " AND ("
								+ selection + ')' : "");
				break;
			}
			break;
		}
		case SMS_REPLY_REPLY_HISTORY:
		case SMS_REPLY_REPLY_HISTORY_ID: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.REPLY_HISTORIES;
			switch (matchResult) {
			case SMS_REPLY_REPLY_HISTORY:
				break;
			case SMS_REPLY_REPLY_HISTORY_ID:
				String replyHistoryId = uri.getLastPathSegment();

				selection = SmsReplyContract.ReplyHistories._ID
						+ "="
						+ replyHistoryId
						+ (TextUtils.isEmpty(selection) == false ? " AND ("
								+ selection + ')' : "");
				break;
			}
			break;
		}
		case SMS_REPLY_APP_WIDGET_ID:
		case SMS_REPLY_APP_WIDGET_ID_ID: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.APP_WIDGET_IDS;
			switch (matchResult) {
			case SMS_REPLY_APP_WIDGET_ID:
				break;
			case SMS_REPLY_APP_WIDGET_ID_ID:
				String appWidgetId = uri.getLastPathSegment();

				selection = SmsReplyContract.SmsReplyAppWidgetIds._ID
						+ "="
						+ appWidgetId
						+ (TextUtils.isEmpty(selection) == false ? " AND ("
								+ selection + ')' : "");
				break;
			}
			break;
		}
		default:
			throw new IllegalArgumentException("Unknown URI: " + uri);
		}
		PhoneUtilityTransaction phoneUtilityTransaction = startTransaction(false);
		try {
			SQLiteDatabase db = phoneUtilityTransaction
					.getDbForTag(SMS_REPLY_CONTACT_TAG);
			result = db.delete(tableName, selection, selectionArgs);
			phoneUtilityTransaction.markSuccessful(false);
			return result;
		} finally {
			endTransaction(false);
		}
	}

	@Override
	public String getType(Uri uri) {
		return null;
	}

	@Override
	public Uri insert(Uri uri, ContentValues values) {
		waitForAccess(writeAccessLatch);

		String tableName = null;
		int matchResult = uriMatcher.match(uri);
		switch (matchResult) {
		case SMS_REPLY_GLOBAL_SETTING: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.GLOBAL_SETTINGS;
			break;
		}
		case SMS_REPLY: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.REPLIES;
			break;
		}
		case SMS_REPLY_TIMES_MODE: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.REPLY_TIMES_MODE;
			break;
		}
		case RESPONSE_NUMBER_FROM: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.RESPONSE_NUMBER_FROM;
			break;
		}
		case REPLY_TO_SPECIFIC_NUMBER: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.REPLY_TO_SPECIFIC_NUMBER;
			break;
		}
		case NONE_REPLY_NUMBER: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.NONE_REPLY_NUMBER;
			break;
		}
		case ACTIVATION_RECORD: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.ACTIVATION_RECORDS;
			break;
		}
		case SMS_REPLY_REPLY_HISTORY: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.REPLY_HISTORIES;
			break;
		}
		case SMS_REPLY_APP_WIDGET_ID: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.APP_WIDGET_IDS;
			break;
		}
		case SMS_REPLY_GLOBAL_SETTING_ID:
		case SMS_REPLY_ID:
		case SMS_REPLY_TIMES_MODE_ID:
		case RESPONSE_NUMBER_FROM_ID:
		case REPLY_TO_SPECIFIC_NUMBER_ID:
		case NONE_REPLY_NUMBER_ID:
		case ACTIVATION_RECORD_ID:
		case SMS_REPLY_REPLY_HISTORY_ID:
		case SMS_REPLY_APP_WIDGET_ID_ID: {
			throw new UnsupportedOperationException(
					"Insert with id does nost support!, matchResult: "
							+ matchResult);
		}
		default:
			throw new IllegalArgumentException("Unknown URI: " + uri);
		}

		PhoneUtilityTransaction phoneUtilityTransaction = startTransaction(false);
		try {
			SQLiteDatabase db = phoneUtilityTransaction
					.getDbForTag(SMS_REPLY_CONTACT_TAG);
			long rowId = db.insert(tableName, null, values);
			if (rowId > 0) {
				Uri result = ContentUris.withAppendedId(uri, rowId);
				phoneUtilityTransaction.markSuccessful(false);
				return result;
			}
		} finally {
			endTransaction(false);
		}
		throw new SQLException("Failed to insert row into " + uri);
	}

	@Override
	public boolean onCreate() {
		this.phoneUtilitySQLiteOpenHelper = new PhoneUtilitySQLiteOpenHelper(
				getContext());
		this.writeAccessLatch = new CountDownLatch(1);
		this.writeAccessLatch.countDown();
		return true;
	}

	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
		SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();

		String tableName = null;

		int matchResult = uriMatcher.match(uri);

		String _order = null;

		switch (matchResult) {
		case SMS_REPLY_GLOBAL_SETTING:
		case SMS_REPLY_GLOBAL_SETTING_ID: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.GLOBAL_SETTINGS;
			_order = TextUtils.isEmpty(sortOrder) == true ? SmsReplyContract.SmsReplyGlobalSettings._ID
					+ " ASC "
					: sortOrder;
			switch (matchResult) {
			case SMS_REPLY_GLOBAL_SETTING:
				break;
			case SMS_REPLY_GLOBAL_SETTING_ID:
				queryBuilder
						.appendWhere(SmsReplyContract.SmsReplyGlobalSettings._ID
								+ "=" + uri.getLastPathSegment());
				break;
			}
			break;
		}
		case SMS_REPLY:
		case SMS_REPLY_ID: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.REPLIES;
			_order = TextUtils.isEmpty(sortOrder) == true ? SmsReplyContract.SmsReplies.CREATEION_DATE_TIME
					+ " ASC "
					: sortOrder;
			switch (matchResult) {
			case SMS_REPLY:
				break;
			case SMS_REPLY_ID:
				queryBuilder.appendWhere(SmsReplyContract.SmsReplies._ID + "="
						+ uri.getLastPathSegment());
				break;
			}
			break;
		}
		case SMS_REPLY_TIMES_MODE:
		case SMS_REPLY_TIMES_MODE_ID: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.REPLY_TIMES_MODE;
			_order = TextUtils.isEmpty(sortOrder) == true ? SmsReplyContract.ReplyTimesModes._ID
					+ " ASC "
					: sortOrder;
			switch (matchResult) {
			case SMS_REPLY_TIMES_MODE:
				break;
			case SMS_REPLY_TIMES_MODE_ID:
				queryBuilder.appendWhere(SmsReplyContract.ReplyTimesModes._ID
						+ "=" + uri.getLastPathSegment());
				break;
			}
			break;
		}
		case RESPONSE_NUMBER_FROM:
		case RESPONSE_NUMBER_FROM_ID: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.RESPONSE_NUMBER_FROM;
			_order = TextUtils.isEmpty(sortOrder) == true ? SmsReplyContract.ResponseNumberFrom._ID
					+ " ASC "
					: sortOrder;
			switch (matchResult) {
			case RESPONSE_NUMBER_FROM:
				break;
			case RESPONSE_NUMBER_FROM_ID:
				queryBuilder
						.appendWhere(SmsReplyContract.ResponseNumberFrom._ID
								+ "=" + uri.getLastPathSegment());
				break;
			}
			break;
		}
		case REPLY_TO_SPECIFIC_NUMBER:
		case REPLY_TO_SPECIFIC_NUMBER_ID: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.REPLY_TO_SPECIFIC_NUMBER;
			_order = TextUtils.isEmpty(sortOrder) == true ? SmsReplyContract.ReplyToSpecificNumbers._ID
					+ " ASC "
					: sortOrder;
			switch (matchResult) {
			case REPLY_TO_SPECIFIC_NUMBER:
				break;
			case REPLY_TO_SPECIFIC_NUMBER_ID:
				queryBuilder
						.appendWhere(SmsReplyContract.ReplyToSpecificNumbers._ID
								+ "=" + uri.getLastPathSegment());
				break;
			}
			break;
		}
		case NONE_REPLY_NUMBER:
		case NONE_REPLY_NUMBER_ID: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.NONE_REPLY_NUMBER;
			_order = TextUtils.isEmpty(sortOrder) == true ? SmsReplyContract.NoneReplyNumbers._ID
					+ " ASC "
					: sortOrder;
			switch (matchResult) {
			case NONE_REPLY_NUMBER:
				break;
			case NONE_REPLY_NUMBER_ID:
				queryBuilder.appendWhere(SmsReplyContract.NoneReplyNumbers._ID
						+ "=" + uri.getLastPathSegment());
				break;
			}
			break;
		}
		case ACTIVATION_RECORD:
		case ACTIVATION_RECORD_ID: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.ACTIVATION_RECORDS;
			_order = TextUtils.isEmpty(sortOrder) == true ? SmsReplyContract.ActivationRecords._ID
					+ " ASC "
					: sortOrder;
			switch (matchResult) {
			case ACTIVATION_RECORD:
				break;
			case ACTIVATION_RECORD_ID:
				queryBuilder.appendWhere(SmsReplyContract.ActivationRecords._ID
						+ "=" + uri.getLastPathSegment());
				break;
			}
			break;
		}
		case SMS_REPLY_REPLY_HISTORY:
		case SMS_REPLY_REPLY_HISTORY_ID: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.REPLY_HISTORIES;
			_order = TextUtils.isEmpty(sortOrder) == true ? SmsReplyContract.ReplyHistories.CREATION_DATE_TIME
					+ " DESC "
					: sortOrder;
			switch (matchResult) {
			case SMS_REPLY_REPLY_HISTORY:
				break;
			case SMS_REPLY_REPLY_HISTORY_ID:
				queryBuilder.appendWhere(SmsReplyContract.ReplyHistories._ID
						+ "=" + uri.getLastPathSegment());
				break;
			}
			break;
		}
		case SMS_REPLY_APP_WIDGET_ID:
		case SMS_REPLY_APP_WIDGET_ID_ID: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.APP_WIDGET_IDS;
			_order = TextUtils.isEmpty(sortOrder) == true ? SmsReplyContract.SmsReplyAppWidgetIds._ID
					+ " DESC "
					: sortOrder;
			switch (matchResult) {
			case SMS_REPLY_REPLY_HISTORY:
				break;
			case SMS_REPLY_REPLY_HISTORY_ID:
				queryBuilder
						.appendWhere(SmsReplyContract.SmsReplyAppWidgetIds._ID
								+ "=" + uri.getLastPathSegment());
				break;
			}
			break;
		}
		default:
			throw new IllegalArgumentException("Unknown URI: " + uri);
		}
		queryBuilder.setTables(tableName);

		SQLiteDatabase database = this.phoneUtilitySQLiteOpenHelper
				.getReadableDatabase();
		Cursor cursor = queryBuilder.query(database, projection, selection,
				selectionArgs, null, null, _order);
		cursor.setNotificationUri(getContext().getContentResolver(), uri);
		return cursor;
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) {

		String tableName = null;
		int matchResult = uriMatcher.match(uri);
		switch (matchResult) {
		case SMS_REPLY_GLOBAL_SETTING:
		case SMS_REPLY_GLOBAL_SETTING_ID: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.GLOBAL_SETTINGS;
			break;
		}
		case SMS_REPLY:
		case SMS_REPLY_ID: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.REPLIES;
			switch (matchResult) {
			case SMS_REPLY:
				break;
			case SMS_REPLY_ID:
				String smsReplyId = uri.getLastPathSegment();

				selection = SmsReplyContract.SmsReplies._ID
						+ "="
						+ smsReplyId
						+ (TextUtils.isEmpty(selection) == false ? " AND ("
								+ selection + ')' : "");
				break;
			}
			break;
		}
		case SMS_REPLY_TIMES_MODE:
		case SMS_REPLY_TIMES_MODE_ID: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.REPLY_TIMES_MODE;
			switch (matchResult) {
			case SMS_REPLY_TIMES_MODE:
				break;
			case SMS_REPLY_TIMES_MODE_ID:
				String replyTimeModesId = uri.getLastPathSegment();

				selection = SmsReplyContract.ReplyTimesModes._ID
						+ "="
						+ replyTimeModesId
						+ (TextUtils.isEmpty(selection) == false ? " AND ("
								+ selection + ')' : "");
				break;
			}
			break;
		}
		case RESPONSE_NUMBER_FROM:
		case RESPONSE_NUMBER_FROM_ID: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.RESPONSE_NUMBER_FROM;
			switch (matchResult) {
			case RESPONSE_NUMBER_FROM:
				break;
			case RESPONSE_NUMBER_FROM_ID:
				String responseNumberFromId = uri.getLastPathSegment();

				selection = SmsReplyContract.ResponseNumberFrom._ID
						+ "="
						+ responseNumberFromId
						+ (TextUtils.isEmpty(selection) == false ? " AND ("
								+ selection + ')' : "");
				break;
			}
			break;
		}
		case REPLY_TO_SPECIFIC_NUMBER:
		case REPLY_TO_SPECIFIC_NUMBER_ID: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.REPLY_TO_SPECIFIC_NUMBER;
			switch (matchResult) {
			case REPLY_TO_SPECIFIC_NUMBER:
				break;
			case REPLY_TO_SPECIFIC_NUMBER_ID:
				String replyToSpecificId = uri.getLastPathSegment();

				selection = SmsReplyContract.ReplyToSpecificNumbers._ID
						+ "="
						+ replyToSpecificId
						+ (TextUtils.isEmpty(selection) == false ? " AND ("
								+ selection + ')' : "");
				break;
			}
			break;
		}
		case NONE_REPLY_NUMBER:
		case NONE_REPLY_NUMBER_ID: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.NONE_REPLY_NUMBER;
			switch (matchResult) {
			case NONE_REPLY_NUMBER:
				break;
			case NONE_REPLY_NUMBER_ID:
				String noneReplyId = uri.getLastPathSegment();

				selection = SmsReplyContract.NoneReplyNumbers._ID
						+ "="
						+ noneReplyId
						+ (TextUtils.isEmpty(selection) == false ? " AND ("
								+ selection + ')' : "");
				break;
			}
			break;
		}
		case ACTIVATION_RECORD:
		case ACTIVATION_RECORD_ID: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.ACTIVATION_RECORDS;
			switch (matchResult) {
			case ACTIVATION_RECORD:
				break;
			case ACTIVATION_RECORD_ID:
				String activationId = uri.getLastPathSegment();

				selection = SmsReplyContract.ActivationRecords._ID
						+ "="
						+ activationId
						+ (TextUtils.isEmpty(selection) == false ? " AND ("
								+ selection + ')' : "");
				break;
			}
			break;
		}
		case SMS_REPLY_REPLY_HISTORY:
		case SMS_REPLY_REPLY_HISTORY_ID: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.REPLY_HISTORIES;
			switch (matchResult) {
			case SMS_REPLY_REPLY_HISTORY:
				break;
			case SMS_REPLY_REPLY_HISTORY_ID:
				String replyHistoryId = uri.getLastPathSegment();

				selection = SmsReplyContract.ReplyHistories._ID
						+ "="
						+ replyHistoryId
						+ (TextUtils.isEmpty(selection) == false ? " AND ("
								+ selection + ')' : "");
				break;
			}
			break;
		}
		case SMS_REPLY_APP_WIDGET_ID:
		case SMS_REPLY_APP_WIDGET_ID_ID: {
			tableName = PhoneUtilitySQLiteOpenHelper.Tables.SMS.Reply.APP_WIDGET_IDS;
			switch (matchResult) {
			case SMS_REPLY_APP_WIDGET_ID:
				break;
			case SMS_REPLY_APP_WIDGET_ID_ID:
				String appWidgetId = uri.getLastPathSegment();

				selection = SmsReplyContract.SmsReplyAppWidgetIds._ID
						+ "="
						+ appWidgetId
						+ (TextUtils.isEmpty(selection) == false ? " AND ("
								+ selection + ')' : "");
				break;
			}
			break;
		}
		default:
			throw new IllegalArgumentException("Unknown URI: " + uri);
		}
		int result = 0;
		PhoneUtilityTransaction phoneUtilityTransaction = startTransaction(false);
		try {
			SQLiteDatabase db = phoneUtilityTransaction
					.getDbForTag(SMS_REPLY_CONTACT_TAG);
			result = db.update(tableName, values, selection, selectionArgs);
			phoneUtilityTransaction.markSuccessful(false);
			return result;
		} finally {
			endTransaction(false);
		}
	}

	@Override
	public ContentProviderResult[] applyBatch(
			ArrayList<ContentProviderOperation> operations)
			throws OperationApplicationException {
		if (operations == null) {
			return null;
		}

		waitForAccess(writeAccessLatch);

		ContentProviderResult[] result = new ContentProviderResult[operations
				.size()];
		int i = 0;
		PhoneUtilityTransaction smsScheduleTransaction = startTransaction(true);
		try {
			for (ContentProviderOperation operation : operations) {
				result[i++] = operation.apply(this, result, i);
			}

			smsScheduleTransaction.markSuccessful(true);
			if (VERBOSE_LOGGING == true) {
				Log.v(LOG_TAG, Arrays.toString(result));
			}
			return result;
		} finally {
			endTransaction(true);
		}
	}

	private void waitForAccess(CountDownLatch latch) {
		if (latch == null) {
			return;
		}

		while (true) {
			try {
				latch.await();
				return;
			} catch (InterruptedException e) {
				Thread.currentThread().interrupt();
			}
		}
	}

	private PhoneUtilityTransaction startTransaction(boolean callerIsBatch) {
		PhoneUtilityTransaction transaction = this.phoneUtilityTransactionHolder
				.get();
		if (transaction == null) {
			transaction = new PhoneUtilityTransaction(callerIsBatch);

			if (this.phoneUtilitySQLiteOpenHelper != null) {
				transaction
						.startTransactionForDb(
								this.phoneUtilitySQLiteOpenHelper
										.getWritableDatabase(),
								SMS_REPLY_CONTACT_TAG, this);

			}
			this.phoneUtilityTransactionHolder.set(transaction);
		}
		return transaction;
	}

	private void endTransaction(boolean callerIsBatch) {
		PhoneUtilityTransaction transaction = this.phoneUtilityTransactionHolder
				.get();

		if (transaction != null && (!transaction.isBatch() || callerIsBatch)) {
			getContext().getContentResolver().notifyChange(
					SmsReplyContract.AUTHORITY_URI, null);
			transaction.finish(callerIsBatch);
			phoneUtilityTransactionHolder.set(null);
		}
	}

	@Override
	public void onBegin() {
		if (VERBOSE_LOGGING) {
			Log.v(LOG_TAG, "onBeginTransaction");
		}
	}

	@Override
	public void onCommit() {
		if (VERBOSE_LOGGING) {
			Log.v(LOG_TAG, "commit transaction");
		}

	}

	@Override
	public void onRollback() {
		if (VERBOSE_LOGGING) {
			Log.v(LOG_TAG, "rollback transaction");
		}

	}
}
